# -*- coding: utf-8 -*-
"""
事件总线抽象层
提供统一的事件发布接口，支持多种实现（内存队列、RabbitMQ、Redis Stream等）
"""
from abc import ABC, abstractmethod
from typing import Dict, Any, Optional
from queue import Queue, Empty
from threading import Thread
from common.logger import create_logger

logger = create_logger("event_bus")


class EventBus(ABC):
    """事件总线抽象接口"""

    @abstractmethod
    def publish(self, event_type: str, payload: Dict[str, Any]) -> None:
        """
        发布事件

        Args:
            event_type: 事件类型（如 ALARM_RAISED, ALARM_RECOVERED）
            payload: 事件载荷数据
        """
        pass

    @abstractmethod
    def start(self) -> None:
        """启动事件总线"""
        pass

    @abstractmethod
    def stop(self) -> None:
        """停止事件总线"""
        pass

    @abstractmethod
    def health_check(self) -> bool:
        """健康检查"""
        pass

    @abstractmethod
    def get_stats(self) -> Dict[str, Any]:
        """获取统计信息"""
        pass


class MemoryEventBus(EventBus):
    """
    基于内存队列的事件总线（适用于单机部署）

    特点：
    - 零延迟：事件立即进入队列
    - 线程安全：使用Python Queue
    - 简单可靠：无需外部依赖
    - 轻量级：适合中小规模部署

    注意：
    - 进程重启会丢失队列中的事件（可接受，告警已保存到数据库）
    - 单机部署限制（无法跨进程）
    """

    def __init__(self, websocket_manager, max_size: int = 10000):
        """
        初始化内存事件总线

        Args:
            websocket_manager: WebSocket管理器实例
            max_size: 队列最大长度，防止内存溢出
        """
        self.queue = Queue(maxsize=max_size)
        self.websocket_manager = websocket_manager
        self.worker_thread: Optional[Thread] = None
        self._running = False
        self.max_size = max_size

        # 统计信息
        self._published_count = 0
        self._processed_count = 0
        self._error_count = 0

    def publish(self, event_type: str, payload: Dict[str, Any]) -> None:
        """
        发布事件到内存队列

        Args:
            event_type: 事件类型
            payload: 事件载荷
        """
        try:
            # 非阻塞方式放入队列
            self.queue.put_nowait((event_type, payload))
            self._published_count += 1
            logger.debug(f"[MemoryEventBus] 事件已发布: {event_type}, alarm_id={payload.get('alarm_id')}")
        except Exception as e:
            self._error_count += 1
            logger.error(f"[MemoryEventBus] 队列已满或发布失败: {e}")
            # 降级策略：直接同步推送（确保关键事件不丢失）
            self._fallback_sync_push(event_type, payload)

    def start(self) -> None:
        """启动后台消费线程"""
        if self._running:
            logger.warning("[MemoryEventBus] 事件总线已在运行中")
            return

        self._running = True
        self.worker_thread = Thread(
            target=self._consume_events,
            name="EventBusWorker",
            daemon=True
        )
        self.worker_thread.start()
        logger.info("[MemoryEventBus] 内存事件总线已启动")

    def stop(self) -> None:
        """优雅停止事件总线"""
        if not self._running:
            return

        logger.info("[MemoryEventBus] 正在停止事件总线...")
        self._running = False

        # 等待队列清空（最多5秒）
        if self.worker_thread:
            self.worker_thread.join(timeout=5)

        # 记录未处理事件数
        remaining = self.queue.qsize()
        if remaining > 0:
            logger.warning(f"[MemoryEventBus] 停止时仍有 {remaining} 个事件未处理")

        logger.info("[MemoryEventBus] 事件总线已停止")

    def health_check(self) -> bool:
        """
        健康检查

        Returns:
            bool: True表示健康
        """
        if not self._running:
            return False

        # 检查队列使用率（超过90%视为不健康）
        queue_usage = self.queue.qsize() / self.max_size
        if queue_usage > 0.9:
            logger.warning(f"[MemoryEventBus] 队列使用率过高: {queue_usage:.1%}")
            return False

        return True

    def get_stats(self) -> Dict[str, Any]:
        """
        获取统计信息

        Returns:
            dict: 统计数据
        """
        return {
            "running": self._running,
            "queue_size": self.queue.qsize(),
            "queue_max_size": self.max_size,
            "queue_usage": f"{(self.queue.qsize() / self.max_size * 100):.1f}%",
            "published_count": self._published_count,
            "processed_count": self._processed_count,
            "error_count": self._error_count,
            "pending_count": self._published_count - self._processed_count,
        }

    def _consume_events(self) -> None:
        """后台线程消费事件"""
        logger.info("[MemoryEventBus] 事件消费线程已启动")

        while self._running:
            try:
                # 带超时的阻塞获取（1秒），便于优雅退出
                event_type, payload = self.queue.get(timeout=1)

                # 推送到WebSocket
                self._push_to_websocket(event_type, payload)

                self._processed_count += 1
                self.queue.task_done()

            except Empty:
                # 队列为空，继续等待
                continue
            except Exception as e:
                self._error_count += 1
                logger.error(f"[MemoryEventBus] 事件处理失败: {e}", exc_info=True)

        logger.info("[MemoryEventBus] 事件消费线程已退出")

    def _push_to_websocket(self, event_type: str, payload: Dict[str, Any]) -> None:
        """
        推送事件到WebSocket

        Args:
            event_type: 事件类型
            payload: 事件载荷
        """
        try:
            alarm_id = payload.get('alarm_id')
            meter_code = payload.get('meter_code')
            alarm_type = payload.get('alarm_type')

            logger.debug(
                f"[MemoryEventBus] 推送WebSocket: {event_type}, "
                f"alarm_id={alarm_id}, meter_code={meter_code}, alarm_type={alarm_type}"
            )

            # 根据事件类型处理
            if event_type == "ALARM_RAISED":
                self._broadcast_alarm_raised(payload)
            elif event_type == "ALARM_RECOVERED":
                self._broadcast_alarm_recovered(payload)
            elif event_type == "WORK_ORDER_CLOSED":
                logger.debug(f"[MemoryEventBus] 工单关闭事件不推送: {alarm_id}")
            else:
                logger.warning(f"[MemoryEventBus] 未知事件类型: {event_type}")

        except Exception as e:
            logger.error(f"[MemoryEventBus] WebSocket推送失败: {e}", exc_info=True)
            raise

    def _broadcast_alarm_raised(self, payload: Dict[str, Any]) -> None:
        """广播新告警"""
        import asyncio
        from app.routers.dashboard_router import broadcast_new_alert

        # 在新线程中运行异步函数
        try:
            loop = asyncio.get_event_loop()
        except RuntimeError:
            # 如果当前线程没有事件循环，创建一个
            loop = asyncio.new_event_loop()
            asyncio.set_event_loop(loop)

        # 使用run_coroutine_threadsafe在主线程的事件循环中执行
        if loop.is_running():
            asyncio.run_coroutine_threadsafe(broadcast_new_alert(payload, action="new"), loop)
        else:
            # 如果循环未运行，直接执行
            loop.run_until_complete(broadcast_new_alert(payload, action="new"))

    def _broadcast_alarm_recovered(self, payload: Dict[str, Any]) -> None:
        """广播告警恢复"""
        import asyncio
        from app.routers.dashboard_router import broadcast_new_alert

        try:
            loop = asyncio.get_event_loop()
        except RuntimeError:
            loop = asyncio.new_event_loop()
            asyncio.set_event_loop(loop)

        if loop.is_running():
            asyncio.run_coroutine_threadsafe(broadcast_new_alert(payload, action="recovered"), loop)
        else:
            loop.run_until_complete(broadcast_new_alert(payload, action="recovered"))

    def _fallback_sync_push(self, event_type: str, payload: Dict[str, Any]) -> None:
        """
        降级策略：队列满时直接同步推送

        Args:
            event_type: 事件类型
            payload: 事件载荷
        """
        try:
            logger.warning(f"[MemoryEventBus] 队列已满，使用同步推送: {event_type}")
            self._push_to_websocket(event_type, payload)
        except Exception as e:
            logger.error(f"[MemoryEventBus] 同步推送也失败: {e}", exc_info=True)


# 全局事件总线实例
_event_bus_instance: Optional[EventBus] = None


def init_event_bus(websocket_manager, bus_type: str = "memory", **kwargs) -> EventBus:
    """
    初始化全局事件总线

    Args:
        websocket_manager: WebSocket管理器
        bus_type: 总线类型（memory/redis/rabbitmq）
        **kwargs: 额外配置参数

    Returns:
        EventBus: 事件总线实例
    """
    global _event_bus_instance

    if _event_bus_instance is not None:
        logger.warning("[EventBus] 事件总线已初始化，将停止旧实例")
        _event_bus_instance.stop()

    if bus_type == "memory":
        _event_bus_instance = MemoryEventBus(
            websocket_manager=websocket_manager,
            max_size=kwargs.get('max_size', 10000)
        )
    # 未来可扩展其他实现
    # elif bus_type == "redis":
    #     _event_bus_instance = RedisStreamEventBus(...)
    # elif bus_type == "rabbitmq":
    #     _event_bus_instance = RabbitMQEventBus(...)
    else:
        raise ValueError(f"不支持的事件总线类型: {bus_type}")

    _event_bus_instance.start()
    logger.info(f"[EventBus] 全局事件总线已初始化: {bus_type}")

    return _event_bus_instance


def get_event_bus() -> EventBus:
    """
    获取全局事件总线实例

    Returns:
        EventBus: 事件总线实例

    Raises:
        RuntimeError: 如果事件总线未初始化
    """
    if _event_bus_instance is None:
        raise RuntimeError("事件总线未初始化，请先调用init_event_bus()")
    return _event_bus_instance
